﻿
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Text;
using System.Threading;

namespace WgFrame.Net
{
    public class SupportClass
    {
		public delegate int IntegerMillisecondsDelegate();

		public class ThreadSafeRandom
		{
			private static readonly Random _r = new Random();

			public static int Next()
			{
				lock (_r)
				{
					return _r.Next();
				}
			}
		}

		private static List<Thread> threadList;

		private static readonly object ThreadListLock = new object();

		protected internal static IntegerMillisecondsDelegate IntegerMilliseconds = () => Environment.TickCount;

		private static uint[] crcLookupTable;

		public static List<MethodInfo> GetMethods(Type type, Type attribute)
		{
			List<MethodInfo> fittingMethods = new List<MethodInfo>();
			if (type == null)
			{
				return fittingMethods;
			}
			MethodInfo[] declaredMethods = type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			MethodInfo[] array = declaredMethods;
			foreach (MethodInfo methodInfo in array)
			{
				if (attribute == null || methodInfo.IsDefined(attribute, inherit: false))
				{
					fittingMethods.Add(methodInfo);
				}
			}
			return fittingMethods;
		}

		public static long GetTickCount()
		{
			return IntegerMilliseconds();
		}

		public static byte StartBackgroundCalls(Func<bool> myThread, int millisecondsInterval = 100, string taskName = "")
		{
			lock (ThreadListLock)
			{
				if (threadList == null)
				{
					threadList = new List<Thread>();
				}
				Thread thread = new Thread((ThreadStart)delegate
				{
					try
					{
						while (myThread())
						{
							Thread.Sleep(millisecondsInterval);
						}
					}
					catch (ThreadAbortException)
					{
					}
				});
				if (!string.IsNullOrEmpty(taskName))
				{
					thread.Name = taskName;
				}
				thread.IsBackground = true;
				thread.Start();
				for (int i = 0; i < threadList.Count; i++)
				{
					if (threadList[i] == null)
					{
						threadList[i] = thread;
						return (byte)i;
					}
				}
				if (threadList.Count >= 255)
				{
					throw new NotSupportedException("StartBackgroundCalls() can run a maximum of 255 threads.");
				}
				threadList.Add(thread);
				return (byte)(threadList.Count - 1);
			}
		}

		public static bool StopBackgroundCalls(byte id)
		{
			lock (ThreadListLock)
			{
				if (threadList == null || id >= threadList.Count || threadList[id] == null)
				{
					return false;
				}
				threadList[id].Abort();
				threadList[id] = null;
				return true;
			}
		}

		public static bool StopAllBackgroundCalls()
		{
			lock (ThreadListLock)
			{
				if (threadList == null)
				{
					return false;
				}
				foreach (Thread thread in threadList)
				{
					thread?.Abort();
				}
				threadList.Clear();
			}
			return true;
		}

		public static void WriteStackTrace(Exception throwable, TextWriter stream)
		{
			if (stream != null)
			{
				stream.WriteLine(throwable.ToString());
				stream.WriteLine(throwable.StackTrace);
				stream.Flush();
			}
			else
			{
				Debug.WriteLine(throwable.ToString());
				Debug.WriteLine(throwable.StackTrace);
			}
		}

		public static void WriteStackTrace(Exception throwable)
		{
			WriteStackTrace(throwable, null);
		}

		public static string DictionaryToString(IDictionary dictionary)
		{
			return DictionaryToString(dictionary, includeTypes: true);
		}

		public static string DictionaryToString(IDictionary dictionary, bool includeTypes)
		{
			if (dictionary == null)
			{
				return "null";
			}
			StringBuilder sb = new StringBuilder();
			sb.Append("{");
			foreach (object key in dictionary.Keys)
			{
				if (sb.Length > 1)
				{
					sb.Append(", ");
				}
				Type valueType;
				string value;
				if (dictionary[key] == null)
				{
					valueType = typeof(object);
					value = "null";
				}
				else
				{
					valueType = dictionary[key].GetType();
					value = dictionary[key].ToString();
				}
				if (typeof(IDictionary) == valueType || typeof(Hashtable) == valueType)
				{
					value = DictionaryToString((IDictionary)dictionary[key]);
				}
				if (typeof(string[]) == valueType)
				{
					value = string.Format("{{{0}}}", string.Join(",", (string[])dictionary[key]));
				}
				if (typeof(byte[]) == valueType)
				{
					value = $"byte[{((byte[])dictionary[key]).Length}]";
				}
				if (includeTypes)
				{
					sb.AppendFormat("({0}){1}=({2}){3}", key.GetType().Name, key, valueType.Name, value);
				}
				else
				{
					sb.AppendFormat("{0}={1}", key, value);
				}
			}
			sb.Append("}");
			return sb.ToString();
		}

		public static string ByteArrayToString(byte[] list)
		{
			if (list == null)
			{
				return string.Empty;
			}
			return BitConverter.ToString(list);
		}

		private static uint[] InitializeTable(uint polynomial)
		{
			uint[] createTable = new uint[256];
			for (int i = 0; i < 256; i++)
			{
				uint entry = (uint)i;
				for (int j = 0; j < 8; j++)
				{
					entry = (((entry & 1) != 1) ? (entry >> 1) : ((entry >> 1) ^ polynomial));
				}
				createTable[i] = entry;
			}
			return createTable;
		}

		public static uint CalculateCrc(byte[] buffer, int length)
		{
			uint crc = uint.MaxValue;
			uint poly = 3988292384u;
			if (crcLookupTable == null)
			{
				crcLookupTable = InitializeTable(poly);
			}
			for (int bufferIndex = 0; bufferIndex < length; bufferIndex++)
			{
				crc = (crc >> 8) ^ crcLookupTable[buffer[bufferIndex] ^ (crc & 0xFF)];
			}
			return crc;
		}
	}
}

